package org.example.async;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.concurrent.ExecutorConfigurationSupport;
import org.springframework.stereotype.Component;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;

@Component
@Slf4j
class SpringAsyncRunner implements CommandLineRunner {

    @Autowired
    private AsyncService service;

    @Autowired
    private Executor executor;

    private CountDownLatch taskCountDownLatch;
    private CountDownLatch logCountDownLatch;

    @Override
    public void run(String... args) throws Exception {
        /*
         * 最后一个 taskCountDown 会释放 taskCountDownLatch，而这时 logOnTaskCompleted() 还没有执行，
         * 可能导致主线程在最后一个 logOnTaskCompleted() 之前执行 onAllTaskCompleted()。
         *
         * 所以，为了保证在 onAllTaskCompleted() 之前执行 logOnTaskCompleted()，需要再加一个 logCountDownLatch，
         * 主线程等待 logCountDownLatch 释放了再执行 onAllTaskCompleted()。
         */
        repeatTask(10);
        waitAllTaskCompleted();
        onAllTaskCompleted();
    }

    private void repeatTask(int n) {
        taskCountDownLatch = new CountDownLatch(n);
        logCountDownLatch = new CountDownLatch(n);
        for (int i = 0; i < n; i++) {
            service.doInBackground((result, throwable) -> {
                taskCountDownLatch.countDown();
                logOnTaskCompleted();
                logCountDownLatch.countDown();
            });
        }
    }

    private void logOnTaskCompleted() {
        log.info("Left tasks: " + (taskCountDownLatch.getCount()));
    }

    private void waitAllTaskCompleted() throws InterruptedException {
        log.info("Wait execute tasks...");
        logCountDownLatch.await();
    }

    private void onAllTaskCompleted() {
        log.info("All tasks completed");
        shutdown();
    }

    private void shutdown() {
        log.info("Shutdown executor");
        if (executor instanceof ExecutorConfigurationSupport support) {
            support.initiateShutdown();
        }
    }
}
